#include "Node.hpp"

bool Node::AttachObject(Object* objectIn)
{
	AttachedObjects.push_back(objectIn);
	return true;
}

void Node::DrawAll()
{
	FixCamera();
	for(unsigned int i = 0; i < AttachedObjects.size(); i ++)
	{
		AttachedObjects[i] -> Draw();
	}
}

void Node::Rotate(float angle, int axis)
{
    if(axis < 0 || axis > 2)
        return;
    rotations[axis] = angle;
  
}

void Node::Scale(float sc)
{
	scale = sc;
}

void Node::FixCamera()
{
    glEnable(GL_DEPTH_TEST);
	int width, height;

    // Get window size. It may start out different from the requested
    // size, and will change if the user resizes the window.
    glfwGetWindowSize( &width, &height );
    if(height<=0) height=1; // Safeguard against iconified/closed window
    // Set viewport. This is the pixel rectangle we want to draw into.
    glViewport( 0, 0, width, height ); // The entire window

    //glm::mat4 modelview_matrix;
    if(CameraUsed == NULL)
    {
		std::cout << "Error: Camera not initialized" << std::endl;
		return;
	}
	Vector3 CameraPos = CameraUsed -> GetPosition();
	Vector3 CameraLookAt = CameraUsed -> GetLookAt();
	
	ModelviewMatrix = glm::lookAt(glm::vec3(CameraPos.x, CameraPos.y, CameraPos.z), glm::vec3(CameraLookAt.x, CameraLookAt.y, CameraLookAt.z), glm::vec3(0.0, 1.0, 0.0));
    ProjectionMatrix = glm::perspective(45.0f, 1.0f*float(width)/float(height), 0.1f, 20.0f);
    ModelviewMatrix = glm::scale
    (
		ModelviewMatrix,
		glm::vec3(scale, scale, scale)
    );
	ModelviewMatrix = glm::translate
	(
		ModelviewMatrix,
		translation.ToGLMVector()
	);
    ModelviewMatrix = glm::rotate
    (
		ModelviewMatrix,
		rotations[0], glm::vec3(1.0f, 0.0f, 0.0f)
	);
	ModelviewMatrix = glm::rotate
    (
		ModelviewMatrix,
		rotations[1], glm::vec3(0.0f, 1.0f, 0.0f)
	);
	ModelviewMatrix = glm::rotate
    (
		ModelviewMatrix,
		rotations[2], glm::vec3(0.0f, 0.0f, 1.0f)
	);
    glm::mat3 Inv = glm::transpose(glm::inverse(glm::mat3(ModelviewMatrix)));
	//*/
    GLint uniform_modelview;
    GLint uniform_projection;
    GLint uniform_m_3x3_inv_transp;
    GLint color;
    for(unsigned int i = 0; i < AttachedObjects.size(); i ++)
    {
		AttachedObjects[i] -> GetShader() -> Use();
		uniform_modelview = glGetUniformLocation(AttachedObjects[i] -> GetShader() -> GetProgram(), "modelview_matrix");
		if(uniform_modelview < 0)
		{
            std::cout<<"Modelview not found" << std::endl;
		}

		uniform_projection = glGetUniformLocation(AttachedObjects[i] -> GetShader() -> GetProgram(), "projection_matrix");
		if(uniform_projection < 0)
		{
            std::cout<<"Projection not found" << std::endl;
		}
		uniform_m_3x3_inv_transp = glGetUniformLocation(AttachedObjects[i] -> GetShader() -> GetProgram(), "m_3x3_inv_transp");
		color = glGetUniformLocation(AttachedObjects[i] -> GetShader() -> GetProgram(), "color");
		if(uniform_m_3x3_inv_transp < 0)
		{
            std::cout<<"Inverse modelview not found" << std::endl;
		}
		
		
		glUniformMatrix4fv(uniform_modelview, 1, GL_FALSE, glm::value_ptr(ModelviewMatrix));
		glUniformMatrix4fv(uniform_projection, 1, GL_FALSE, glm::value_ptr(ProjectionMatrix));
		glUniformMatrix3fv(uniform_m_3x3_inv_transp, 1, GL_FALSE, glm::value_ptr(Inv));
		glUniform3f(color, AttachedObjects[i] -> color.x, AttachedObjects[i] -> color.y, AttachedObjects[i] -> color.z);
		
		Shader::UseNoShader();
	}

}


void Node::Translate(const Vector3& v)
{
	translation = v;
}

void Node::AttachCamera(Camera* kamera)
{
	CameraUsed = kamera;
}
